"""
Used a formulate a dimenional query.
"""
from dsbq.models import Stat

class StatQuery(object):
    """
    Builds a stat query.
    """
    def __init__(self, context, stat_name, dimension_tuples=None):
        """
        Builds a stat query.
        """
        self.context = context
        self.stat_name = stat_name
        self.dimension_tuples = dimension_tuples or []
        self.future = None # holds the future for the results, populated with populate()

    def add_dimension_filter(self, name, value):
        """
        Adds a dimension filter.
        """
        self.dimension_tuples.append((name, value))

    def __iter__(self):
        """
        Returns an iterator over the results. Waits on the future.
        """
        if self.future is None:
            raise ValueError('You must execute the query with run() (or runAll()) before iterating.')
        return iter(self.future.get_result())

    def run(self, order=False):
        """
        Executes a single query.

        Kwargs:
            order if True, the query results will be ordered by row_num. When using this option
                  you will need to specify custom indexes in your index.yaml:

                  indexes:

                    - kind: Stat
                      properties:
                      - name: context
                      - name: stat_name
                      - name: row_num

                    # this index is required only if you are specifying dimensions on your query
                    - kind: Stat
                      properties:
                      - name: context
                      - name: d
                      - name: stat_name
                      - name: row_num
        """
        query = Stat.query(Stat.context==self.context, Stat.stat_name==self.stat_name)
        if order:
            query = query.order(Stat.row_num)
        for name, value in self.dimension_tuples:
            query = query.filter(Stat.dimension==Stat.encode_dimension(name, value))
        self.future = query.fetch_async(1000)

    @classmethod
    def run_all(cls, queries, order=False):
        if not queries:
            raise ValueError('queries is required.')
        if not isinstance(queries, list):
            queries = [queries]
        if not all(isinstance(q, cls) for q in queries):
            raise ValueError('All items of queries must be StatQuery objects.')
        # kick off async queries for each stat
        for query in queries:
            query.run(order=order)
